package com.lazyframework.security.admin.authentication.provider;

import com.lazyframework.security.admin.authentication.JwtAuthenticationToken;
import com.lazyframework.security.admin.properties.JwtProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

import java.util.Base64;

/**
 * 提供JWT认证
 * Create by lazy in 2019.09.17
 */
public class JwtAuthenticationProvider implements AuthenticationProvider {

    private JwtProperties properties;

    private String authenticationType;

    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        // Filter authentication header. eg: Bearer
        String token = authentication.getPrincipal().toString();
        if (token.startsWith(authenticationType)) {
            token = token.substring(authenticationType.length() + 1);
        }

        // Validate JWT
        Jwt jwt = Jwts.parser()
                .setSigningKey(Base64.getEncoder().encodeToString(properties.getSecretKey().getBytes()))
                .parse(token);

        // Get username from JWT
        Claims claims = (Claims) jwt.getBody();
        String username = (String) claims.get("username");

        // Get user authorities
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        // Build UserDetails
        return new JwtAuthenticationToken(userDetails);
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return JwtAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public void setProperties(JwtProperties properties) {
        this.properties = properties;
    }

    public void setAuthenticationType(String authenticationType) {
        this.authenticationType = authenticationType;
    }
}
